<?php

/**
 * @author Thibaut Cromphaut, Gaïtano Boeraeve, Mathias Helin, Dimitry Dierickx
 * @copyright  Copyright (c) 2011 Artevelde University College Ghent 
 */

class Application_Model_BookMapper extends Ahs_Model_Mapper
{

    public function __construct(array $options = null)
    {
        parent::__construct($options);
        $this->DbTableName = 'Application_Model_DbTable_Books';
        $this->PropertiesMap    = array(
            "Id"            => "book_id",
            "AuthorId"      => "book_author_id",
            "Title"         => "book_title",
            "Subtitle"      => "book_subtitle",
            "Description"   => "book_description",
            "Image"         => "book_image",
            "CreationDate"  => "book_creationdate",
            "ModifiedDate"  => "book_modifieddate",
            "DeletedDate"   => "book_deleteddate",
        );
    }
    
    /**
     * Get all books
     * 
     * @param integer $page_nr      If you wish to use paging, pass the page-number. To disable paging, 
     *                              pass null as value (default) and return all rows.
     * @param integer $nr_results   The number of results per page, defaults to 10.
     * @return Array(Application_Model_Book)
     */
    public function fetchAll($page_nr=null, $nr_results=10)
    {        
        $table = $this->getDbTable();
        $select = $table->select();
        $select->where(''.$this->getColumn('DeletedDate').' IS NULL')
               ->order(''.$this->getColumn('CreationDate').' DESC');
        
        if($page_nr != null && $page_nr > 0)
            $select->limitPage($page_nr, $nr_results);
        
        $rows = $table->fetchAll($select);
        return $this->_toBooks($rows);
    }
    
    /**
     * Get a book by its ID
     * 
     * @param integer $book_id
     * @return Application_Model_Book
     */
    public function fetchById($book_id)
    {
        $table = $this->getDbTable();
        $select = $table->select();
        $select->where(
                    ''.$this->getColumn('Id').' = :id'
                        . ' AND ' .
                    ''.$this->getColumn('DeletedDate').' IS NULL'
                )
                ->bind(array(':id' => $book_id));
        $row = $table->fetchRow($select);    
        return $this->_toBook($row);
    }
    
    /**
     * Search books by (part of) their name
     * 
     * @param string $name
     * @return Array(Application_Model_Book) 
     */
    public function fetchByName($name)
    {
        $table = $this->getDbTable();
        $select = $table->select();
        $select->where(
                    ''.$this->getColumn('Title').' LIKE :name'
                        . ' AND ' .
                    ''.$this->getColumn('DeletedDate').' IS NULL'
                )
               ->bind( array(':name' => "%{$name}%") )
               ->order(''.$this->getColumn('Title').' ASC')
               ->limit(10);
        $rows = $table->fetchAll($select);
        return $this->_toBooks($rows);
    }
    
    /**
     * Get all books by name for an author
     * 
     * @return Array(Application_Model_Article)
     */
    public function fetchByNameAndAuthorId($book_name, $author_id)
    {
        $table = $this->getDbTable();
        $select = $table->select()->setIntegrityCheck(false);
        $select->where(
                    ''.$this->getColumn('Title').'  LIKE :title'                    
                       . ' AND ' .
                    ''.$this->getColumn('AuthorId').' = :id'
                       . ' AND ' .
                    ''.$this->getColumn('DeletedDate').' IS NULL'
                 )
               ->bind(array(':title' => "%{$book_name}%", ':id' => $author_id))
               ->order(''.$this->getColumn('Title').' ASC');
        $rows = $table->fetchAll($select);
        return $this->_toBooks($rows);
    }
    
    /**
     * Search books by course
     * 
     * @param integer $course_id
     * @return Array(Application_Model_Book) 
     */
    public function fetchByCourseId($course_id, $page_nr=null, $nr_results=10)
    {
        $table = $this->getDbTable();
        $select = $table->select()->setIntegrityCheck(false);
        $select->from('books')->joinInner(array('chb' => 'courses_has_books'),'books.'.$this->getColumn('Id').'=chb.books_book_id')
               ->where('chb.courses_course_id = :id')
               ->bind(array(':id' => $course_id))
               ->order(''.$this->getColumn('CreationDate').' DESC');
        
        if($page_nr != null && $page_nr > 0)
            $select->limitPage($page_nr, $nr_results);
        
        $rows = $table->fetchAll($select);
        
        return $this->_toBooks($rows);
    }
    
    /**
     * Get all books for an author
     * 
     * @param integer $author_id
     * @param integer $page_nr      If you wish to use paging, pass the page-number. To disable paging, 
     *                              pass null as value (default) and return all rows.
     * @param integer $nr_results   The number of results per page, defaults to 10.
     * @return Array(Application_Model_Book)
     */
    public function fetchByAuthorId($author_id, $page_nr=null, $nr_results=10)
    {
        $table = $this->getDbTable();
        $select = $table->select()->setIntegrityCheck(false);
        $select->where(
                    ''.$this->getColumn('AuthorId').' = :id'
                       . ' AND ' .
                    ''.$this->getColumn('DeletedDate').' IS NULL'
                 )
               ->bind(array(':id' => $author_id))
               ->order(''.$this->getColumn('CreationDate').' DESC');
        
        if($page_nr != null && $page_nr > 0)
            $select->limitPage($page_nr, $nr_results);
        
        $rows = $table->fetchAll($select);
        return $this->_toBooks($rows);
    }
    
    /**
     * Get all books the user has added to his readinglist
     * 
     * @param integer $user_id
     * @param integer $page_nr      If you wish to use paging, pass the page-number. To disable paging, 
     *                              pass null as value (default) and return all rows.
     * @param integer $nr_results   The number of results per page, defaults to 10.
     * @return Array(Application_Model_Book->Id) 
     */
    public function fetchByUserId($user_id, $page_nr=null, $nr_results=10)
    {
        $ids    = array();
        
        $table = $this->getDbTable();
        $select = $table->select()->setIntegrityCheck(false);
        $select->from('books')->joinInner(array('uhb' => 'users_has_books'),'books.'.$this->getColumn('Id').'=uhb.books_book_id')
               ->where(
                    'uhb.users_user_id = :id'
                       . ' AND ' .
                    ''.$this->getColumn('DeletedDate').' IS NULL'
                 )
               ->bind(array(':id' => $user_id))
               ->order(''.$this->getColumn('CreationDate').' DESC');
        
        if($page_nr != null && $page_nr > 0)
            $select->limitPage($page_nr, $nr_results);
        
        $rows = $table->fetchAll($select);
        
        return $this->_toBooks($rows);
    }
    
    /**
     * Get all recent books
     * 
     * @param integer $days         The number of days to go back in time to fetch items.
     * @param integer $page_nr      If you wish to use paging, pass the page-number. To disable paging, 
     *                              pass null as value (default) and return all rows.
     * @param integer $nr_results   The number of results per page, defaults to 10.
     * @return Array(Application_Model_Book) 
     */
    public function fetchByRecent($days=30, $page_nr=null, $nr_results=10)
    {
        $interval   = new Zend_Db_Expr('DATE_SUB(CURDATE(), INTERVAL '.$days.' DAY)');
        $table = $this->getDbTable();
        $select = $table->select();
        $select->where(
                    ''.$this->getColumn('CreationDate').' > '.$interval
                        . ' AND ' .
                    ''.$this->getColumn('DeletedDate').' IS NULL'
                )
               ->order(''.$this->getColumn('CreationDate').' DESC');
        
        if($page_nr != null && $page_nr > 0)
            $select->limitPage($page_nr, $nr_results);
        
        $rows = $table->fetchAll($select);
        return $this->_toBooks($rows);
    }
    
    /**
     * Get an array of book ids for a given user
     * 
     * @param integer $user_id
     * @return Array(Application_Model_Book->Id) 
     */
    public function getBookIdsByUserId($user_id)
    {
        $ids    = array();
        
        $table = $this->getDbTable();
        $select = $table->select()->setIntegrityCheck(false);
        $select->from('books')->joinInner(array('uhb' => 'users_has_books'),'books.'.$this->getColumn('Id').'=uhb.books_book_id')
               ->where(
                    'uhb.users_user_id = :id'
                       . ' AND ' .
                    ''.$this->getColumn('DeletedDate').' IS NULL'
                 )
               ->bind(array(':id' => $user_id));
        $rows = $table->fetchAll($select);
        
        if($rows != null && count($rows))
        {
            foreach($rows as $row)
            {
                $ids[]  = $row[''.$this->getColumn('Id').''];
            }
        }
        
        return $ids;
    }
    
    /**
     * Get the total number of books
     * 
     * @return integer
     */
    public function getCount()
    {
        $ids    = array();
        
        $table = $this->getDbTable();
        $select = $table->select();
        $select->from($table, array('count(*) as count'));
        $select->where(''.$this->getColumn('DeletedDate').' IS NULL');
        
        $rows = $table->fetchAll($select);
        
        return $rows[0]->count;
    }
    
    /**
     * Get the total number of books for this user's readinglist
     * 
     * @param integer $user_id
     * @return integer
     */
    public function getCountByUserId($user_id)
    {
        $ids    = array();
        
        $table = $this->getDbTable();
        $select = $table->select()->setIntegrityCheck(false);
        $select->from($table, array('count(*) as count'));
        $select->joinInner(array('uhb' => 'users_has_books'),'books.'.$this->getColumn('Id').'=uhb.books_book_id')
               ->where(
                    'uhb.users_user_id = :id'
                       . ' AND ' .
                    'books.'.$this->getColumn('DeletedDate').' IS NULL'
                 )
               ->bind(array(':id' => $user_id));
        $rows = $table->fetchAll($select);
        
        return $rows[0]->count;
    }
    
    /**
     * Get the total number of books for this author
     * 
     * @param integer $author_id
     * @return integer
     */
    public function getCountByAuthorId($author_id)
    {
        $ids    = array();        
        $table = $this->getDbTable();
        $select = $table->select()->setIntegrityCheck(false);
        $select->from($table, array('count(*) as count'));
        $select->where(
                    ''.$this->getColumn('AuthorId').' = :id'
                       . ' AND ' .
                    ''.$this->getColumn('DeletedDate').' IS NULL'
                 )
               ->bind(array(':id' => $author_id));
        $rows = $table->fetchAll($select);        
        
        return $rows[0]->count;
    }
    
    /**
     * Get the total number of books for this course
     * 
     * @param integer $course_id
     * @return integer
     */
    public function getCountByCourseId($course_id)
    {
        $ids    = array();
        
        $table = $this->getDbTable();
        $select = $table->select()->setIntegrityCheck(false);
        $select->from($table, array('count(*) as count'));
        $select->joinInner(array('chb' => 'courses_has_books'),'books.'.$this->getColumn('Id').'=chb.books_book_id')
               ->where('chb.courses_course_id = :id')
               ->bind(array(':id' => $course_id));
        $rows = $table->fetchAll($select);
        
        return $rows[0]->count;
    }
    
    /**
     * Get the total number of recent books
     * 
     * @param integer $days         The number of days to go back in time to fetch items.
     * @return integer
     */
    public function getCountByRecent($days=30)
    {
        $interval   = new Zend_Db_Expr('DATE_SUB(CURDATE(), INTERVAL '.$days.' DAY)');
        $table = $this->getDbTable();
        $select = $table->select();
        $select->from($table, array('count(*) as count'));
        $select->where(
                    ''.$this->getColumn('CreationDate').' > ('.$interval.')'
                        . ' AND ' .
                    ''.$this->getColumn('DeletedDate').' IS NULL'
                );
        $rows = $table->fetchAll($select);
        
        return $rows[0]->count;
    }
    
    /**
     * Add a book to a course
     * 
     * @param integer $book_id
     * @param integer $course_id 
     */
    public function addBookToCourse($book_id, $course_id)
    {
        $table  = new Application_Model_DbTable_CourseHasBooks();
        $table->insert(array(
            "courses_course_id" => $course_id,
            "books_book_id"     => $book_id,
        ));
    }
    
    /**
     * Save an book
     *
     * @param Application_Model_Book $book
     */
    public function save(Application_Model_Book $book)
    {
        $book_id = $book->Id;
        
        $data = $this->_getTableValues($book, array("Id"));
        $data[$this->getColumn("ModifiedDate")] = new Zend_Db_Expr('NOW()');
        
        if(null == $book_id)
        {
            // Set some default values
            $data[$this->getColumn("CreationDate")] = new Zend_Db_Expr('NOW()');
            $data[$this->getColumn("AuthorId")]     = $this->getLoggedInUserId();
            
            // Insert and get the id
            $book_id    = $this->getDbTable()->insert($data);
            
            // Add this course to the user's courses
            $mapperUser = new Application_Model_UserMapper();
            $mapperUser->addBookToUser($book_id, $this->getLoggedInUserId());
        }
        else
        {
            $this->getDbTable()->update($data, array(''.$this->getColumn('Id').' = ?' => $book_id));
        }
        
        return $book_id;
    }
    
    /**
     * Delete a book by id
     *
     * @param integer $id
     */
    public function delete($id)
    {   
        if (null != $id)
        {
            $data[$this->getColumn('DeletedDate')] = new Zend_Db_Expr('NOW()');
            $this->getDbTable()->update($data, array(''.$this->getColumn('Id').' = ?' => $id));
        }
    }
    
    /**
     * Undelete a book by id
     *
     * @param integer $id
     */
    public function undelete($id)
    {   
        if (null != $id)
        {
            $data[$this->getColumn('DeletedDate')] = new Zend_Db_Expr('NULL');
            $this->getDbTable()->update($data, array(''.$this->getColumn('Id').' = ?' => $id));
        } 
    }
    
    /**
     * Convert a row to object
     * 
     * @param Zend_Db_Table_Row_Abstract $row
     * @return Application_Model_Book
     */
    private function _toBook(Zend_Db_Table_Row_Abstract $row = null)
    {
        // Create our object
        $object = new Application_Model_Book();
        
        // Only go on if we actually have a row
        if($row)
        {
            // We have a propertiesmap, let's try to map it back to an object
            foreach($this->PropertiesMap as $key=>$column)
            {
                if(isset($row[$column]))
                    $object->$key      = $row[$column];
            }
        }

        return $object;
    }

    /**
     * Convert a rowset to an array of objects
     * 
     * @param Zend_Db_Table_Rowset_Abstract $rows
     * @return Array(Application_Model_Article)
     */
    private function _toBooks(Zend_Db_Table_Rowset_Abstract $rows = null)
    {
        $results = array();
        if ($rows)
        {
            foreach ($rows as $row)
            {
                $results[] = $this->_toBook($row);
            }
        }
        return $results;
    }
}


